With &&
The downside with using an if
statement is that we need to pull the logic up, away from the rest of the markup. While this is perfectly valid, it can make it harder to understand how a component is structured, especially in larger and more-complex components. We'd have to hop all over the place to understand what gets returned!
Fortunately, there's a way for us to embed if
logic right in our JSX: using the &&
operator.
Here's how we'd do it:
Code Playground
In JavaScript, &&
is a control flow operator. It works quite a bit like if/else, except it's an expression instead of a statement.
To help us understand what's actually happening here, let's take a look at the exact same logic, but expressed using if
/else
:
function Friend({ name, isOnline }) { let prefix; if (isOnline) { prefix = <div className="green-dot" />; } else { prefix = isOnline; }
return ( <li className="friend"> {prefix} {name} </li> );}
The &&
operator is said to be a “control flow” operator because, like if/else, it will always result in one of two paths being taken.
If the left-hand value (isOnline
) is falsy, the expression short-circuits, and evaluates to isOnline
, which resolves to false
. If that value is truthy, however, it evaluates to whatever's on the right-hand side of the operator (<div className="green-dot" />
).
You can think of the &&
operator a bit like a nightclub bouncer. If you try to get in with a fake ID, the bouncer won't let you access the React element on the other side. If the value is truthy, though, the bouncer unhooks the velvet rope, and we're allowed to access the React element.
This concept is explained in greater depth in the JavaScript primer lesson “Logical Operators” 👀.
Common gotcha: the number zero
Consider this situation:
function App() { const shoppingList = ['avocado', 'banana', 'cinnamon']; const numOfItems = shoppingList.length;
return ( <div> {numOfItems && ( <ShoppingList items={shoppingList} /> )} </div> );}
We have a component, ShoppingList
, and it only really makes sense to render that component if we have at least 1 item in our shopping list.
If you've been using JavaScript for a while, you might know that every number in JS is truthy except 0. 0 is the only falsy number, just like how ''
is the only falsy string.
Therefore, it seems to make sense to do things this way. If numOfItems
has at least 1 item in it, it will be truthy, and we'll render the <ShoppingList>
element. If we have 0 items, we should skip it.
But check out what happens when we actually run this setup:
Code Playground
We wind up with 0
being rendered!
Why is this happening? We need to keep two things in mind:
- The
&&
operator doesn't returntrue
orfalse
. It returns either the left-hand side or the right-hand side. So, when our list is empty, this expression evaluates to0
. - React will render any number you give it, even zero!
React will ignore most falsy values like false
or null
, but it won't ignore the number zero.
In fact, let's see how React handles all of the different falsy values:
Code Playground
React will actually render the number 0
. And when we think about it, this makes sense. There are lots of situations where we'd want to render this number:
function Banner({ ticketsRemaining }) { return ( <h2> Number of JIRA tickets left: {ticketsRemaining}. </h2> );}
If ticketsRemaining
is equal to 0
, we want to show the number 0
, not an empty space!
Solution: Always use boolean values with &&
To avoid having random 0
characters sprinkled around your application, I suggest following a “golden rule”: make sure that the left-hand side of &&
always evaluates to a boolean value, either true
or false
.
For example, we can check if the number is greater than zero:
function App() { const shoppingList = ['avocado', 'banana', 'cinnamon']; const numOfItems = shoppingList.length;
return ( <div> {numOfItems > 0 && ( <ShoppingList items={shoppingList} /> )} </div> );}
I really like this approach. We're being really specific with what the condition is: if we have 1 or more items in the shopping list, we should render the <ShoppingList>
element. The “greater than” operator (>
) will always produce a boolean value, either true
or false
.
We can also convert any non-boolean value to a boolean value with !!
:
function App() { const shoppingList = ['avocado', 'banana', 'cinnamon']; const numOfItems = shoppingList.length;
return ( <div> {!!numOfItems && ( <ShoppingList items={shoppingList} /> )} </div> );}
If you're not sure what's going on here with !!
, check out the JavaScript Primer lesson on Truthy and Falsy 👀.